package com.zhq.blog.core.domain;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.util.Assert;

@SuppressWarnings("rawtypes")
@NoRepositoryBean
public class BaseRepositoryImpl<T extends BasePersistentDomain> extends
		SimpleJpaRepository<T, Long> implements BaseRepository<T> {

	private Log logger = LogFactory.getLog(this.getClass());

	// private EntityManager entityManager;

	public BaseRepositoryImpl(Class<T> domainClass, EntityManager entityManager) {
		super(domainClass, entityManager);
		// this.entityManager = entityManager;
	}

	public Specification<T> findByField(final String fieldName,
			final Object field) {
		return new Specification<T>() {
			@Override
			public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query,
					CriteriaBuilder builder) {
				logger.debug("find by " + fieldName + " and " + field);
				return builder.equal(root.get(fieldName), field);
			}
		};
	}

	@Override
	public List<T> find(String fieldName, Object field) {
		return this.findAll(findByField(fieldName, field));
	}

	@Override
	public boolean has(String fieldName, Object field) {
		return count(fieldName, field) > 0;
	}

	@Override
	public long count(String fieldName, Object field) {
		return this.count(findByField(fieldName, field));
	}

	public void delete(Long id) {

		T entity = findOne(id);

		delete(entity);

	}

	public void delete(T entity) {

		Assert.notNull(entity, "The entity must not be null!");

		logger.debug("update entity [" + entity
				+ "] set deleteflag = true begin............");

		entity.setDeleted(true);

		super.saveAndFlush(entity);

		logger.debug("update entity set deleteflag = true over............");

	}

	public void delete(Iterable<? extends T> entities) {

		Assert.notNull(entities, "The given Iterable of entities not be null!");

		for (T entity : entities) {

			delete(entity);

		}

	}

	public Specification<T> notDeleted() {
        return new Specification<T>() {
            @Override
            public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
                return builder.not(root.<Boolean>get("deleted"));
            }
        };
	}

	public Specification<T> isDeleted() {
        return new Specification<T>() {
            @Override
            public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
                return builder.isTrue(root.<Boolean>get("deleted"));
            }
        };

	}
}
